<?php
// +----------------------------------------------------------------------
// | Category 类型服务
// +----------------------------------------------------------------------
// | 主要服务于Category数据处理
// +----------------------------------------------------------------------
// | 错误编码头 240xxx
// +----------------------------------------------------------------------

namespace common\service;


use common\exception\LogicException;
use common\model\StepCategoryModel;
use common\model\TaskModel;
use common\model\TaskRelationModel;
use support\ErrorCode;
use support\SingletonTrait;
use think\module\Module;

class StepCategoryService
{
    use SingletonTrait;


    /**
     * 查询二级分类列表
     * @param $extendFilter
     * @return array|false|mixed|string
     */
    public function secondLevelList($extendFilter = [])
    {
        $topStepCategoryList = model(StepCategoryModel::class)
            ->where(['parent_id' => 0])
//            ->field('id')
            ->select();
        if (empty($topStepCategoryList)) {
            return [];
        }
        $topStepCategoryEntityId = array_column($topStepCategoryList, 'entity_id', 'id');
        $filter = [
            'parent_id' => ['IN', array_column($topStepCategoryList, 'id')],
            'is_deprecate' => 'no',
        ];
        if (!empty($extendFilter)) {
            $filter[] = $extendFilter;
        }
        $list = model(StepCategoryModel::class)->where($filter)->order("id ASC")->select();
        foreach ($list as &$item) {
            $item['module_code'] = '';
            $entityModuleId = $topStepCategoryEntityId[$item['parent_id']] ?? 0;
            if (empty($entityModuleId)) {
                continue;
            }
            $module = module_by_id($entityModuleId);
            if (in_array($module['code'], ['design', 'asset', 'level'])) {
                $item['module_code'] = 'asset';
            } elseif (in_array($module['code'], ['shot', 'storyboard'])) {
                $item['module_code'] = 'shot';
            } else {
                $item['module_code'] = $module['code'];
            }
        }

        return $list;
    }

    /**
     * 查询展示的分类列表
     * @return array|false|mixed|string
     */
    public function showSecondLevelList()
    {
        $topStepCategoryList = StepCategoryService::getInstance()->getList(['parent_id' => 0, 'is_show' => 'yes', 'entity_id' => ['GT', 0]], '*');
        if (empty($topStepCategoryList)) {
            return [];
        }
        $topStepCategoryEntityId = array_column($topStepCategoryList, 'entity_id', 'id');

        $filter = [
            'parent_id' => ['IN', array_column($topStepCategoryList, 'id')],
            'is_deprecate' => 'no',
            'is_show' => 'yes'
        ];
        $list = StepCategoryService::getInstance()->getList($filter, '*', 'show_index ASC,id ASC');
        foreach ($list as &$item) {
            $item['module_code'] = '';
            $entityModuleId = $topStepCategoryEntityId[$item['parent_id']] ?? 0;
            if (empty($entityModuleId)) {
                continue;
            }
            $module = module_by_id($entityModuleId);
            $item['real_module_code'] = $module['code'];
            if (in_array($module['code'], ['design', 'asset', 'level'])) {
                $item['module_code'] = 'asset';
            } elseif (in_array($module['code'], ['shot', 'storyboard'])) {
                $item['module_code'] = 'shot';
            } else {
                $item['module_code'] = $module['code'];
            }
        }
        return $list;
    }

    /**
     * 查询项目模板展示的分类列表
     * @return array
     */
    public function ShowProjectSecondLevelList()
    {
        // 查询当前项目所在的项目模板
        $filter = [
            'ext_filter' => [
                'is_show' => 'yes'
            ]
        ];
        $findStatisticalStepTemplateData = TemplateService::getInstance()->findStatisticalStepTemplate($filter);
        $data = array_filter($findStatisticalStepTemplateData, function ($tmp) {
            return $tmp['is_show'] == 'yes';
        });
        return array_values($data);
    }

    /**
     * 查询工序分类
     * @param $filter
     * @param $fields
     * @return array|false|mixed|string
     */
    public function getOne($filter, $fields)
    {
        return model(StepCategoryModel::class)->where($filter)->field($fields)->cache(C('database.default_query_cache_time'))->find();
    }

    /**
     * 查询工序分类列表
     * @param $filter
     * @param $fields
     * @param string $order
     * @return array|false|mixed|string
     */
    public function getList($filter, $fields, $order = '')
    {
        return model(StepCategoryModel::class)->where($filter)->field($fields)->order($order)->cache(C('database.default_query_cache_time'))->select();
    }

    /**
     * 环节上下游关系
     * @param $filter
     * @return array
     */
    public function upstreamRelation($filter)
    {
        $stepCategoryList = $this->getList($filter, 'id,name,code');
        if (empty($stepCategoryList)) {
            return [];
        }
        $relationData = [];
        foreach ($stepCategoryList as $stepCategory) {
            $relationData[$stepCategory['id']] = [
                'upstream' => [],
                'downstream' => [],
            ];
        }
        $producerStepCategoryConfig = OptionsService::getInstance()->getProducerStepCategoryConfig(false);
        foreach ($producerStepCategoryConfig as $producerStepCategoryConfigItem) {
            $currentStepCategoryId = intval($producerStepCategoryConfigItem['id']);
            if (empty($relationData[$currentStepCategoryId]['upstream'])) {
                $relationData[$currentStepCategoryId]['upstream'] = [];
            }
            foreach ($producerStepCategoryConfigItem['upstream_step_category_id'] as $stepCategoryId) {
                $stepCategoryId = intval($stepCategoryId);
                if ($stepCategoryId <= 0) {
                    continue;
                }
                // 组装下游关系
                if (empty($relationData[$stepCategoryId]['downstream'])) {
                    $relationData[$stepCategoryId]['downstream'] = [];
                }
                if (!in_array($currentStepCategoryId, $relationData[$stepCategoryId]['downstream'])) {
                    $relationData[$stepCategoryId]['downstream'][] = $currentStepCategoryId;
                }
                if (!in_array($stepCategoryId, $relationData[$currentStepCategoryId]['upstream'])) {
                    $relationData[$currentStepCategoryId]['upstream'][] = $stepCategoryId;
                }
            }
        }
        foreach ($stepCategoryList as &$stepCategory) {
            $stepCategory['upstream'] = $relationData[$stepCategory['id']]['upstream'];
            $stepCategory['downstream'] = $relationData[$stepCategory['id']]['downstream'];
        }
        return $stepCategoryList;
    }

    /**
     * 查询环节模块
     * @param $stepCategoryId
     * @return array
     */
    public function getStepCategoryTopModule($stepCategoryId)
    {
        // 判断当前要查询的实体是什么类型
        $stepCategory = $this->getOne(['id' => $stepCategoryId], '*');
        if (empty($stepCategory)) {
            throw new LogicException('second level category not found', ErrorCode::STEP_CATEGORY_NOT_FOUND);
        }
        $topStepCategory = $this->getOne(['id' => $stepCategory['parent_id']], '*');
        if (empty($topStepCategory)) {
            throw new LogicException('top category not found', ErrorCode::STEP_CATEGORY_NOT_FOUND);
        }
        return module_by_id($topStepCategory['entity_id']);
    }

    /**
     * 获取指定任务的下游环节列表，按当前任务、下游环节、环节内任务组织
     * @param $param
     * @return array
     */
    public function getNextStepCategoryFromTaskRelation($param)
    {
        $param = query_array_construct([
            'task_id_list' => 'split_array|array_map,intval',
            'task_step_type' => 'split_array|array_map,strval',
            'exclude_task_status' => 'split_array|array_map,intval',
        ], $param);
        $nextStepCategoryList = [];
        if (!empty($param['task_id_list'])) {
            $where = [
                'id' => ['in', $param['task_id_list']],
                'step_type' => ['in', implode(',', $param['task_step_type'])],
                'task.json->>"$.task_status"' => ['IN', implode(',', $param['exclude_task_status'])]
            ];

            $taskList = model(TaskModel::class)
                ->where($where)
                ->field('id,project_id')
                ->select();

            foreach ($taskList as $taskItem) {
                $projectId = $taskItem['project_id'] ?? 0;
                $nextStepCategoryRelationList = model(TaskRelationModel::class)
                    ->setSuffix(sprintf('_project_%d', $projectId))
                    ->alias('task_relation')
                    ->join('task_relation_tag on task_relation_tag.task_id = task_relation.source_task_id and task_relation_tag.link_module_code in ("step_category", "show_step_category")')
                    ->where([
                        'task_relation.relation_type' => ['IN', [TaskRelationModel::RELATION_TYPE_UPSTREAM, TaskRelationModel::RELATION_TYPE_ENTITY, TaskRelationModel::RELATION_TYPE_RELATION]],
                        'task_relation.target_task_id' => $taskItem['id']
                    ])
                    ->field('task_relation.target_task_id as current_id, task_relation.source_task_id as downstream_id, task_relation_tag.link_id as step_category_id')
                    ->select();
                if (!empty($nextStepCategoryRelationList)) {
                    foreach ($nextStepCategoryRelationList as $nextStepCategoryRelationItem) {
                        $nextStepCategoryList[] = $nextStepCategoryRelationItem;
                    }
                }
            }
        }
        $nextStepCategoryList = array_group_by($nextStepCategoryList, 'current_id');
        $nextStepCategoryMap = [];
        foreach ($param['task_id_list'] as $taskId) {
            $currentTaskDownstreamMap = [];
            foreach ($nextStepCategoryList[$taskId] ?? [] as $item) {
                if (!isset($currentTaskDownstreamMap[$item['step_category_id']])) {
                    $currentTaskDownstreamMap[$item['step_category_id']] = [];
                }
                if (!in_array($item['downstream_id'], $currentTaskDownstreamMap[$item['step_category_id']])) {
                    $currentTaskDownstreamMap[$item['step_category_id']][] = $item['downstream_id'];
                }
            }
            $nextStepCategoryMap[$taskId] = $currentTaskDownstreamMap;
        }
        return $nextStepCategoryMap;
    }

    /**
     * 根据实体分类工序分类列表ids
     * @param $entityModuleCode
     * @return array
     */
    public function getStepCategoryListByEntity($entityModuleCode)
    {
        // 剧本 episode
        // 镜头 storyboard + shot
        // 资产 design + asset + level
        // Module::$moduleDictData['module_index_by_code']['episode']['id']
        if (!in_array($entityModuleCode, ['episode', 'shot', 'asset'])) {
            return [];
        }

        // 1. 获取分类绑定的实体moduleId列表
        $moduleIds = [];
        switch ($entityModuleCode) {
            case 'episode':
                $moduleIds[] = Module::$moduleDictData['module_index_by_code']['episode']['id'];
                break;
            case 'shot':
                $moduleIds[] = Module::$moduleDictData['module_index_by_code']['storyboard']['id'];
                $moduleIds[] = Module::$moduleDictData['module_index_by_code']['shot']['id'];
                break;
            case 'asset':
                $moduleIds[] = Module::$moduleDictData['module_index_by_code']['design']['id'];
                $moduleIds[] = Module::$moduleDictData['module_index_by_code']['asset']['id'];
                $moduleIds[] = Module::$moduleDictData['module_index_by_code']['level']['id'];
                break;
        }

        // 2. 获取二级分类列表
        $stepCategoryIds = [];
        $stepCategoryIdData = model(StepCategoryModel::class)
            ->field('id')
            ->where([
                'entity_id' => ['IN', $moduleIds],
                'parent_id' => ['NEQ', 0]
            ])
            ->select();

        if (!empty($stepCategoryIdData)) {
            $stepCategoryIds = array_column($stepCategoryIdData, 'id');
        }

        return $stepCategoryIds;
    }
}
